package wator.model;

/**
 * An instance of this class represents a 3-dimensional vector.
 * 
 * @see IntegerVector
 */
public class Integer3DVector extends IntegerVector {
	
	private int x, y, z;
	
	/**
	 * Creates a 3-dimensional vector with given elements.
	 * 
	 * @param x the first element
	 * @param y the second element
	 * @param z the third element
	 */
	public Integer3DVector(int x, int y, int z) {
		this.x = x;
		this.y = y;
		this.z = z;
	}

	/* (non-Javadoc)
	 * @see wator.model.IntegerVector#getDimension()
	 */
	@Override
	public int getDimension() {
		return 3;
	}
	
	/* (non-Javadoc)
	 * @see wator.model.IntegerVector#mul(int)
	 */
	@Override
	public IntegerVector mul(int scalar) {
		return new Integer3DVector(x * scalar, y * scalar, z * scalar);
	}
	
	/* (non-Javadoc)
	 * @see wator.model.IntegerVector#mul(double)
	 */
	@Override
	public IntegerVector mul(double scalar) {
		return new Integer3DVector(
				(int) Math.round(((double) x) * scalar),
				(int) Math.round(((double) y) * scalar),
				(int) Math.round(((double) z) * scalar));
	}

	/* (non-Javadoc)
	 * @see wator.model.IntegerVector#div(int)
	 */
	@Override
	public IntegerVector div(int scalar) {
		return new Integer3DVector(x / scalar, y / scalar, z / scalar);
	}

	/* (non-Javadoc)
	 * @see wator.model.IntegerVector#mul(wator.model.IntegerVector)
	 */
	@Override
	public IntegerVector mul(IntegerVector v2) {
		Integer3DVector o = (Integer3DVector) v2;
		return new Integer3DVector(x * o.x, y * o.y, z * o.z);
	}

	/* (non-Javadoc)
	 * @see wator.model.IntegerVector#add(wator.model.IntegerVector)
	 */
	@Override
	public IntegerVector add(IntegerVector v2) {
		Integer3DVector o = (Integer3DVector) v2;
		return new Integer3DVector(x + o.x, y + o.y, z + o.z);
	}

	/* (non-Javadoc)
	 * @see wator.model.IntegerVector#sub(wator.model.IntegerVector)
	 */
	@Override
	public IntegerVector sub(IntegerVector v2) {
		Integer3DVector o = (Integer3DVector) v2;
		return new Integer3DVector(x - o.x, y - o.y, z - o.z);
	}

	/* (non-Javadoc)
	 * @see wator.model.IntegerVector#mod(wator.model.IntegerVector)
	 */
	@Override
	public IntegerVector mod(IntegerVector v2) {
		Integer3DVector o = (Integer3DVector) v2;
		return new Integer3DVector(x % o.x, y % o.y, z % o.z);
	}

	/* (non-Javadoc)
	 * @see wator.model.IntegerVector#generateRandomVectorInRange()
	 */
	@Override
	public IntegerVector generateRandomVectorInRange() {
		return new Integer3DVector(
				(int) (Math.random() * x),
				(int) (Math.random() * y),
				(int) (Math.random() * z));
	}

	/* (non-Javadoc)
	 * @see wator.model.IntegerVector#max()
	 */
	@Override
	public int max() {
		return x < y ? (y < z ? z : y ) : (x < z ? z : x);
	}

	/* (non-Javadoc)
	 * @see wator.model.IntegerVector#min()
	 */
	@Override
	public int min() {
		return x > y ? (y > z ? z : y ) : (x > z ? z : x);
	}

	/* (non-Javadoc)
	 * @see wator.model.IntegerVector#euclideanDistance2(IntegerVector)
	 */
	@Override
	public int euclideanDistance2(IntegerVector v2) {
		Integer3DVector o = (Integer3DVector) v2;
		return (o.x - x) * (o.x - x) + 
				(o.y - y) * (o.y - y) +
				(o.z - z) * (o.z - z);
	}

	/* (non-Javadoc)
	 * @see wator.model.IntegerVector#length2()
	 */
	@Override
	public int length2() {
		return x * x + y * y + z * z;
	}

	/* (non-Javadoc)
	 * @see wator.model.IntegerVector#reduce(IntegerVector)
	 */
	@Override
	public IntegerVector reduce(IntegerVector sizeVector) {
		Integer3DVector s = (Integer3DVector) sizeVector;
		int signX = x > 0 ? 1 : -1;
		int signY = y > 0 ? 1 : -1;
		int signZ = z > 0 ? 1 : -1;
		return new Integer3DVector(
				signX * x <= (s.x / 2) ? x : (x - signX * s.x),
				signY * y <= (s.y / 2) ? y : (y - signY * s.y),
				signZ * z <= (s.z / 2) ? z : (z - signZ * s.z));
	}

	/* (non-Javadoc)
	 * @see wator.model.IntegerVector#vol()
	 */
	@Override
	public int vol() {
		return x * y * z;
	}

	/* (non-Javadoc)
	 * @see wator.model.IntegerVector#compareTo(wator.model.IntegerVector)
	 */
	@Override
	public int compareTo(IntegerVector arg0) {
		if (equals(arg0)) {
			return 0;
		}
		Integer3DVector o = (Integer3DVector) arg0;
		int thisLength = length2();
		int thatLength = arg0.length2();
		if (thisLength == thatLength) {
			return x != o.x ? x - o.x : (
						y != o.y ? y - o.y : (
							z != o.z ? z - o.z : 0));
		}
		return thisLength - thatLength;
	}
	
	/* (non-Javadoc)
	 * @see java.lang.Object#equals(java.lang.Object)
	 */
	@Override
	public boolean equals(Object obj) {
		if (obj == null) {
			return false;
		}
		if (!(obj instanceof Integer3DVector)) {
			return false;
		}
		Integer3DVector o = (Integer3DVector) obj;
		return x == o.x && y == o.y && z == o.z;
	}

	/* (non-Javadoc)
	 * @see java.lang.Object#hashCode()
	 */
	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + x;
		result = prime * result + y;
		result = prime * result + z;
		return result;
	}

	/**
	 * Get the x-value (first dimension) of the vector.
	 * 
	 * @return the x value
	 */
	public int getX() {
		return x;
	}

	/**
	 * Get the y-value (first dimension) of the vector.
	 * 
	 * @return the y value
	 */
	public int getY() {
		return y;
	}

	/**
	 * Get the z-value (first dimension) of the vector.
	 * 
	 * @return the z value
	 */
	public int getZ() {
		return z;
	}

	/* (non-Javadoc)
	 * @see java.lang.Object#toString()
	 */
	@Override
	public String toString() {
		return "(" + x + ", " + y + " " + z + ")";
	}
}
